import {
  Body,
  Controller,
  Get,
  Module,
  Param,
  Post,
  Request,
  UseInterceptors,
} from "@nestjs/common";
import { PrismaClient } from "@prisma/client";
import { WebResult } from "src/common/web.result";
import { ArticleSetCreateDTO } from "./dto/set-create.dto";
import { LoginInterceptor } from "src/user/interceptor/login.interceptor";
import { FastifyRequest } from "fastify";
import { UserTokenService } from "src/user/token.service";
import { SetAddArticleDto } from "./dto/set-add-article.dto";
import { UserModule } from "src/user/user.module";

@Controller("/article/set")
export class ArticleSetController {
  constructor(
    private readonly prisma: PrismaClient,
    private readonly userTokenService: UserTokenService,
  ) {}

  @Post(["/", "/create"])
  @UseInterceptors(LoginInterceptor)
  async createArticleSet(
    @Request() request: FastifyRequest,
    @Body() setDTO: ArticleSetCreateDTO,
  ) {
    const uid = this.userTokenService.getUserIDFromRequest(request);

    try {
      const set = await this.prisma.article_set.create({
        data: {
          owner_id: uid,
          name: setDTO.name,
          description: setDTO.description,
        },
      });
      if (!set) {
        return WebResult.failure(undefined, "create article set failed");
      }
      return WebResult.success(undefined, "合集创建成功");
    } catch (e) {
      console.error(e);
      return WebResult.failure(undefined, "内部错误");
    }
  }

  @Post("/add/article")
  @UseInterceptors(LoginInterceptor)
  async setAddArticle(
    @Request() request: FastifyRequest,
    @Body() addDTO: SetAddArticleDto,
  ) {
    const uid = this.userTokenService.getUserIDFromRequest(request);

    try {
      const set = await this.prisma.article_set.findUnique({
        select: {
          owner_id: true,
        },
        where: { id: addDTO.set_id },
      });
      if (!set) {
        return WebResult.failure(undefined, "不存在的合集");
      } else if (set.owner_id !== uid) {
        return WebResult.failure(undefined, "没有权限");
      }
      const article = await this.prisma.article.findUnique({
        select: {
          publisher_id: true,
        },
        where: { id: addDTO.article_id },
      });
      if (!article) {
        return WebResult.failure(undefined, "不存在的文章");
      } else if (article.publisher_id !== uid) {
        return WebResult.failure(undefined, "没有权限");
      }
      const relation = await this.prisma.article_set_relation.create({
        data: {
          set_id: addDTO.set_id,
          article_id: addDTO.article_id,
        },
      });
      if (!relation) {
        return WebResult.failure(undefined, "添加失败");
      }
      return WebResult.success(undefined, "添加成功");
    } catch (e) {
      console.error(e);
      return WebResult.failure(undefined, "内部错误");
    }
  }

  /**
   * 根据集合ID获取集合详情
   * @param id 集合的唯一标识符
   * @returns 返回集合的详细信息，如果失败则返回错误信息
   */
  @Get(["/:id", "/id/:id"])
  async getArticleSetByID(@Param("id") id: string) {
    try {
      const setID = parseInt(id);
      if (isNaN(setID)) {
        return WebResult.failure(undefined, "id is not a number");
      }
      const Set = await this.prisma.article_set.findUnique({
        select: {
          id: true,
          owner_id: true,
          name: true,
          description: true,
        },
        where: {
          id: setID,
        },
      });
      return WebResult.success(Set);
    } catch (e) {
      console.error(e);
      return WebResult.failure(undefined, "failed to get article Set");
    }
  }

  /**
   * 根据主人ID获取集合列表
   * @param id 主人的唯一标识符
   * @returns 返回主人的所有集合列表，如果失败则返回错误信息
   */
  @Get("/owner/:id")
  async getArticleSetsByOwnerID(@Param("id") id: string) {
    try {
      const ownerID = parseInt(id);
      if (isNaN(ownerID)) {
        return WebResult.failure(undefined, "id is not a number");
      }
      const sets = await this.prisma.article_set.findMany({
        select: {
          id: true,
          owner_id: true,
          name: true,
          description: true,
          create_time: true,
        },
        where: {
          owner_id: ownerID,
        },
      });
      return WebResult.success(sets);
    } catch (e) {
      console.error(e);
      return WebResult.failure(undefined, "failed to get article Sets");
    }
  }

  /**
   * 根据文章ID获取集合ID列表
   * @param id 文章的唯一标识符
   * @returns 返回该文章所有集合的ID列表，如果失败则返回错误信息
   */
  @Get(["/article/:id", "/article/id/:id"])
  async getSetIDsByArticleID(@Param("id") id: string) {
    try {
      const articleID = parseInt(id);
      if (isNaN(articleID)) {
        return WebResult.failure(undefined, "id is not a number");
      }
      const relationArray = await this.prisma.article_set_relation.findMany({
        select: {
          set_id: true,
        },
        where: {
          article_id: articleID,
        },
      });
      const ids = new Array(relationArray.length);
      for (let i = 0; i < relationArray.length; i++) {
        ids[i] = relationArray[i].set_id;
      }
      return WebResult.success(ids);
    } catch (e) {
      console.error(e);
      return WebResult.failure(undefined, "failed to get Set id");
    }
  }

  /**
   * 根据集合名称搜索集合列表
   * @param name 集合名称
   * @returns 返回包含指定名称的集合列表，如果失败则返回错误信息
   */
  @Get(["/search/:name", "/search/name/:name"])
  async searchSetsByName(@Param("name") name: string) {
    try {
      const sets = await this.prisma.article_set.findMany({
        select: {
          id: true,
          owner_id: true,
          name: true,
          description: true,
          create_time: true,
        },
        where: {
          name: {
            contains: name,
          },
        },
      });
      return WebResult.success(sets);
    } catch (e) {
      console.error(e);
      return WebResult.failure(undefined, "failed to get article Sets");
    }
  }

  /**
   * 根据集合ID获取文章ID列表
   * @param id 集合的唯一标识符
   * @returns 返回该集合包含的所有文章ID列表，如果失败则返回错误信息
   */
  @Get([
    "/:id/article",
    "/id/:id/article",
    "/:id/article/id",
    "/:id/article/ids",
    "/id/:id/article/id",
    "/id/:id/article/ids",
  ])
  async getArticleIDsBySetID(@Param("id") id: string) {
    try {
      const setID = parseInt(id);
      if (isNaN(setID)) {
        return WebResult.failure(undefined, "setID is not a number");
      }
      const relationArray = await this.prisma.article_set_relation.findMany({
        select: {
          article_id: true,
        },
        where: {
          id: setID,
        },
      });
      const ids = new Array(relationArray.length);
      for (let i = 0; i < relationArray.length; i++) {
        ids[i] = relationArray[i].article_id;
      }
      return WebResult.success(ids);
    } catch (e) {
      console.error(e);
      return WebResult.failure(undefined, "failed to get article id");
    }
  }
}

@Module({
  imports: [UserModule],
  controllers: [ArticleSetController],
})
export class ArticleSetModule {}
